package com.esteel.settlement.pa.packet;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.Assert;

/**
 * 平安 结算报文 头信息
 * 
 * @author zhangxiuzhi
 *
 */
public class PacketHeader implements Serializable {

	public static int HEADERLEN = 222;
	// 报文编码GBK
	public static String GBK = "01";
	// 报文编码UTF8
	public static String UTF8 = "02";
	// 报文编码Unicode
	public static String UNICODE = "03";
	// 报文编码iso-8859-1
	public static String ISO885901 = "04";

	// 通讯协议为tcp/ip
	public static String TCPIP = "01";
	// 通讯协议为http
	public static String HTTP = "02";
	// 通讯协议为webservice
	public static String WEBSERVICE = "03";

	public static SimpleDateFormat SFDate = new SimpleDateFormat("yyyyMMdd");
	public static SimpleDateFormat SFTime = new SimpleDateFormat("HHmmss");
	public static SimpleDateFormat SFALLDate = new SimpleDateFormat("yyyyMMddHHmmss");

	Charset charset = Charset.forName("GBK");
	

	// 1 C(4) 报文类别 默认 A001
	@Length(max=4,min=4)
	private String packetType = "A001";
	// 2 C(2) 目标系统 默认 03
	@Length(max=2,min=2)
	private String targetSystem = "03";
	// 3 C(2) 报文编码 01:GBK
	@Length(max=2,min=2)
	private String packetEncode = PacketHeader.GBK;
	// 4 C(2) 通讯协议 01:tcp/ip 02:http
	@Length(max=2,min=2)
	private String protocol = PacketHeader.TCPIP;
	// 5 C(20) 银企直连标准代码
	@Length(max=20)
	private String qydm;
	// 6 C(10) 报文长度
	private int packetLength;
	// 7 C(6) 交易吗 统一为000000
	@Length(max=6)
	private String transCode = "000000";
	// 8 C(5) 操作员代码 可选 建议 00000
	@Length(max=5)
	private String counterId = "";
	// 9 C(2) 服务类型 请求:01 应答:02
	@Length(max=2,min=2)
	private String servType;
	// 10 C(8) 交易日期 yyyymmdd
	// private String transDate;
	// 11 C(6) 交易时间 hhmmss
	// private String transTime;
	@NotNull
	private Date tranDate = new Date();
	// 12 C(20) 请求方系统流水
	@Length(max=20)
	@NotNull
	private String thirdLogNo;
	// 13 C(6) 返回码 默认000000
	@Length(max=6)
	private String rspCode = "000000";
	// 14 C(100) 返回描述
	@Length(max=100)
	private String rspMsg = "";
	// 15 C(1) 后续包标志 结束包:0
	@Length(max=1,min=1)
	private String subsequent = "0";
	// 16 C(3) 请求次数
	private int requestCount = 0;
	// 17 C(1) 签名标识 必须填 0
	@Length(max=1,min=1)
	private String signMark = "0";
	// 18 C(1) 签名数据包格式 必须填 1
	@Length(max=1,min=1)
	private String signFormat = "1";
	// 19 C(12) 签名算法 可选
	@Length(max=12)
	private String signAlgorithm = "";
	// 20 C(10) 签名数据长度 必须填 0
	private int signDataLen = 0;
	// C(1) 附件数目 默认为0
	private int affixCount = 0;

	public String getPacketType() {
		return packetType;
	}

	public void setPacketType(String packetType) {
		this.packetType = packetType;
	}

	public String getTargetSystem() {
		return targetSystem;
	}

	public void setTargetSystem(String targetSystem) {
		this.targetSystem = targetSystem;
	}

	public String getPacketEncode() {
		return packetEncode;
	}

	public void setPacketEncode(String packetEncode) {
		this.packetEncode = packetEncode;
	}

	public String getProtocol() {
		return protocol;
	}

	public void setProtocol(String protocol) {
		this.protocol = protocol;
	}

	public String getQydm() {
		return qydm;
	}

	public void setQydm(String qydm) {
		this.qydm = qydm;
	}

	public int getPacketLength() {
		return packetLength;
	}

	public void setPacketLength(int packetLength) {
		this.packetLength = packetLength;
	}

	public String getTransCode() {
		return transCode;
	}

	public void setTransCode(String transCode) {
		this.transCode = transCode;
	}

	public String getCounterId() {
		return counterId;
	}

	public void setCounterId(String counterId) {
		this.counterId = counterId;
	}

	public String getServType() {
		return servType;
	}

	public void setServType(String servType) {
		this.servType = servType;
	}

	// public String getTransDate() {
	// return transDate;
	// }
	// public void setTransDate(String transDate) {
	// this.transDate = transDate;
	// }
	// public String getTransTime() {
	// return transTime;
	// }
	// public void setTransTime(String transTime) {
	// this.transTime = transTime;
	// }
	public String getThirdLogNo() {
		return thirdLogNo;
	}

	public void setThirdLogNo(String thirdLogNo) {
		this.thirdLogNo = thirdLogNo;
	}

	public String getRspCode() {
		return rspCode;
	}

	public void setRspCode(String rspCode) {
		this.rspCode = rspCode;
	}

	public String getRspMsg() {
		return rspMsg;
	}

	public void setRspMsg(String rspMsg) {
		this.rspMsg = rspMsg;
	}

	public String getSubsequent() {
		return subsequent;
	}

	public void setSubsequent(String subsequent) {
		this.subsequent = subsequent;
	}

	public int getRequestCount() {
		return requestCount;
	}

	public void setRequestCount(int requestCount) {
		this.requestCount = requestCount;
	}

	public String getSignMark() {
		return signMark;
	}

	public void setSignMark(String signMark) {
		this.signMark = signMark;
	}

	public String getSignFormat() {
		return signFormat;
	}

	public void setSignFormat(String signFormat) {
		this.signFormat = signFormat;
	}

	public String getSignAlgorithm() {
		return signAlgorithm;
	}

	public void setSignAlgorithm(String signAlgorithm) {
		this.signAlgorithm = signAlgorithm;
	}

	public int getSignDataLen() {
		return signDataLen;
	}

	public void setSignDataLen(int signDataLen) {
		this.signDataLen = signDataLen;
	}

	public int getAffixCount() {
		return affixCount;
	}

	public void setAffixCount(int affixCount) {
		this.affixCount = affixCount;
	}

	public Date getTranDate() {
		return tranDate;
	}

	public void setTranDate(Date tranDate) {
		this.tranDate = tranDate;
	}

	/**
	 * 生成 交易报文的头信息
	 * 
	 * @return
	 */
	public byte[] getPacketHeader() {
		int dstBegin = 0;
		byte[] dst = new byte[222];

		for (int i = 0; i < dst.length; i++) {
			dst[i] = ' ';
		}

		// 1 报文类别
		byte[] src = packetType.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length);
		dstBegin += 4;
		// 2 目标系统
		src = targetSystem.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length);
		dstBegin += 2;
		// 3 报文编码
		src = packetEncode.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length);		
		dstBegin += 2;
		// 4 通讯协议
		src = protocol.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length);				
		dstBegin += 2;
		// 5 企业银企直连标准代码
		if (qydm!=null){
			src = qydm.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length>20?20:src.length);
		}
		dstBegin += 20;
		// 6 接收报文长度
		String packetLengthStr = Integer.toString(this.packetLength);
		for (int i = packetLengthStr.length(); i < 10; i++) {
			packetLengthStr = "0"+packetLengthStr;
		}
		src = packetLengthStr.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length);
		dstBegin += 10;
		// 7 交易码
		if (transCode!=null){
			src = transCode.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length);
		}
		dstBegin += 6;
		// 8 操作员代码
		if (counterId!=null){
			src = counterId.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length);
		}
		dstBegin += 5;
		// 9 服务类型
		if (servType!=null){
			src = servType.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length);
		}
		dstBegin += 2;
		// 10 交易日期
		if (this.tranDate!=null){
			src = SFDate.format(this.getTranDate()).getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length);
		}
		dstBegin += 8;
		// 11 交易时间
			if (this.tranDate!=null){
				src = SFTime.format(this.getTranDate()).getBytes(charset);
				System.arraycopy(src, 0, dst, dstBegin,src.length);
			}
		dstBegin += 6;
		// 12 请求方系统流水
		if (this.thirdLogNo!=null){
			src = thirdLogNo.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length>20?20:src.length);
		}
		dstBegin += 20;
		// 13 返回码
		if (this.rspCode!=null){
			src = rspCode.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length);
		}
		dstBegin += 6;
		// 14 返回描述
		if (this.rspMsg!=null){
			src = rspMsg.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length>100?100:src.length);
		}
		dstBegin += 100;
		// 15 后续包标志
		if (this.subsequent!=null){
			src = subsequent.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, 1);
		}
		dstBegin += 1;
		// 16 请求次数
		String requestCountStr = Integer.toString(this.requestCount);
		for (int i = requestCountStr.length(); i < 3; i++) {
			requestCountStr = "0"+requestCountStr;
		}
		src = requestCountStr.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length);
		dstBegin += 3;
		// 17 签名标识
		if (this.signMark!=null){
			src = signMark.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length);
		}
		dstBegin += 1;
		// 18 签名包 数据格式
		if (this.signFormat!=null){
			src = signFormat.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length);
		}
		dstBegin += 1;
		// 19 签名算法
		if (this.signAlgorithm!=null){
			src = signAlgorithm.getBytes(charset);
			System.arraycopy(src, 0, dst, dstBegin, src.length>12?12:src.length);
		}
		dstBegin += 12;
		// 20 签名数据长度
		String signDataLenStr = Integer.toString(this.signDataLen);
		for (int i = 0; i < 10; i++) {
			dst[dstBegin + i] = '0';
		}
		src = signDataLenStr.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length>10?10:src.length);
		dstBegin += 10;
		// 21 附件数目
		String affixCountStr = Integer.toString(this.affixCount);
		src = affixCountStr.getBytes(charset);
		System.arraycopy(src, 0, dst, dstBegin, src.length);
		
		return dst;
	}

	/**
	 * 解析报文头信息
	 * 
	 * @param header
	 *            报文
	 */
	public void analyze(byte[] src) {
		Assert.isTrue(src.length >= PacketHeader.HEADERLEN, "报文头长度必须大于" + PacketHeader.HEADERLEN);
		int srcPos = 0;
		// 1 报文类别
		byte[] dest = new byte[4];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setPacketType(new String(dest).trim());
		srcPos += 4;
		// 2 目标系统
		dest = new byte[2];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setTargetSystem(new String(dest).trim());
		srcPos += 2;
		// 3 报文编码
		dest = new byte[2];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setPacketEncode(new String(dest).trim());
		srcPos += 2;
		// 4 通讯协议
		dest = new byte[2];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setProtocol(new String(dest).trim());
		srcPos += 2;
		// 5 企业银企直连标准代码
		dest = new byte[20];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setQydm(new String(dest).trim());
		srcPos += 20;
		// 6 接收报文长度
		dest = new byte[10];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setPacketLength(new Integer(new String(dest).trim()).intValue());
		srcPos += 10;
		// 7 交易码
		dest = new byte[6];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setTransCode(new String(dest).trim());
		srcPos += 6;
		// 8 操作员代码
		dest = new byte[5];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setCounterId(new String(dest).trim());
		srcPos += 5;
		// 9 服务类型
		dest = new byte[2];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setServType(new String(dest).trim());
		srcPos += 2;
		dest = new byte[14];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		try {
			this.setTranDate(SFALLDate.parse(new String(dest)));
		} catch (ParseException e) {
		}
		// 10 交易日期
		// dest = new char[8];
		// System.arraycopy(src, srcPos, dest, 0, dest.length);
		// this.setConnectCode(new String(dest));
		srcPos += 8;
		// 11 交易时间
		// dest = new char[8];
		// System.arraycopy(src, srcPos, dest, 0, dest.length);
		// this.setConnectCode(new String(dest));
		srcPos += 6;
		// 12 请求方系统流水
		dest = new byte[20];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setThirdLogNo(new String(dest).trim());
		srcPos += 20;
		// 13 返回码
		dest = new byte[6];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setRspCode(new String(dest).trim());
		srcPos += 6;
		// 14 返回描述
		dest = new byte[100];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setRspMsg(new String(dest,charset).trim());
		srcPos += 100;
		// 15 后续包标志
		dest = new byte[1];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setSubsequent(new String(dest).trim());
		srcPos += 1;
		// 16 请求次数
		dest = new byte[3];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		try{
			this.setRequestCount(new Integer(new String(dest).trim()).intValue());
		}catch(Exception ex){}
		srcPos += 3;
		// 17 签名标识
		dest = new byte[1];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setSignMark(new String(dest));
		srcPos += 1;
		// 18 签名包 数据格
		dest = new byte[1];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setSignFormat(new String(dest));
		srcPos += 1;
		// 19 签名算法
		dest = new byte[12];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setSignAlgorithm(new String(dest).trim());
		srcPos += 12;
		// 20 签名数据长度
		dest = new byte[10];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		this.setSignDataLen(new Integer(new String(dest).trim()).intValue());
		srcPos += 10;
		// 21 附件数目
		dest = new byte[1];
		System.arraycopy(src, srcPos, dest, 0, dest.length);
		try{
			this.setAffixCount(new Integer(new String(dest)).intValue());
		}catch(Exception ex){}
	}

}
